package com.ssy.lingxi.member.merchant.serviceimpl.base;

import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.member.merchant.entity.*;
import com.ssy.lingxi.member.merchant.model.bo.MemberOrgTreeBO;
import com.ssy.lingxi.member.merchant.model.constant.MemberUserAuthTypeEnum;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.request.MemberOrganizationAddVO;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.request.MemberOrganizationDeleteVO;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.request.MemberOrganizationGetVO;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.request.MemberOrganizationUpdateVO;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.response.MemberOrgTreeVO;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.response.MemberOrganizationQueryVO;
import com.ssy.lingxi.member.merchant.repository.MemberOrganizationRepository;
import com.ssy.lingxi.member.merchant.repository.MemberRepository;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberOrganizationService;
import com.ssy.lingxi.member.merchant.utils.MemberOrganizationUtil;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 会员组织机构服务实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2020-06-28
 */
@Service
public class BaseMemberOrganizationServiceImpl implements IBaseMemberOrganizationService {

    @Resource
    private MemberOrganizationRepository memberOrganizationRepository;
    @Resource
    private MemberRepository memberRepository;
    @Resource
    private JPAQueryFactory jpaQueryFactory;


    @Override
    public Wrapper<Void> addMemberOrg(Long memberId, MemberOrganizationAddVO addVO) {
        MemberDO memberDO = memberRepository.findById(memberId).orElse(null);
        if (memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        MemberOrganizationDO upperOrgDO = null;
        if (!addVO.getParentId().equals(0L)) {
            upperOrgDO = memberOrganizationRepository.findById(addVO.getParentId()).orElse(null);
            if (upperOrgDO == null) {
                return Wrapper.fail(ResponseCode.MC_MS_ORGANIZATION_DOES_NOT_EXIST);
            }
        }

        if (memberOrganizationRepository.existsByMemberAndTitle(memberDO, addVO.getTitle())) {
            return Wrapper.fail(ResponseCode.MC_MS_ORGANIZATION_NAME_EXISTS);
        }


        MemberOrganizationDO organizationDO = new MemberOrganizationDO();
        organizationDO.setMember(memberDO);
        organizationDO.setTitle(addVO.getTitle());
        organizationDO.setRemark(StringUtils.hasLength(addVO.getRemark()) ? addVO.getRemark().trim() : "");
        organizationDO.setCode(StringUtils.hasLength(addVO.getCode()) ? addVO.getCode().trim() : "");
        organizationDO.setParentId(addVO.getParentId());

        //层级
        Integer level = upperOrgDO == null ? 1 : upperOrgDO.getLevel() + 1;
        organizationDO.setLevel(level);

        //在同父节点中的顺序
        int maxOrder = 0;
        if (!CollectionUtils.isEmpty(memberDO.getOrgs())) {
            if (upperOrgDO == null) {
                maxOrder = memberDO.getOrgs().stream().filter(org -> org.getLevel().equals(level)).mapToInt(MemberOrganizationDO::getOrder).max().orElse(0);
            } else {
                MemberOrganizationDO finalUpperOrgDO = upperOrgDO;
                maxOrder = memberDO.getOrgs().stream().filter(org -> org.getParentId().equals(finalUpperOrgDO.getId())).mapToInt(MemberOrganizationDO::getOrder).max().orElse(0);
            }
        }
        organizationDO.setOrder(maxOrder + 1);

        //生成Key
        String key = upperOrgDO == null ? String.valueOf(maxOrder + 1) : upperOrgDO.getKey().concat("-").concat(String.valueOf(maxOrder + 1));
        organizationDO.setKey(key);

        memberOrganizationRepository.save(organizationDO);

        return Wrapper.success();
    }

    /**
     * 新增会员门店组织架构菜单
     * @param memberStoreDO 会员门店信息
     * @param memberDO      会员信息
     * @param parentId      父节点id
     * @param orgName       组织机构名称
     * @param orgCode       机构代码
     * @return 操作结果
     */
    public Wrapper<Void> addMemberStoreOrg(MemberStoreDO memberStoreDO, MemberDO memberDO, Long parentId, String orgName, String orgCode) {

        MemberOrganizationDO upperOrgDO = null;
        if (!parentId.equals(0L)) {
            upperOrgDO = memberOrganizationRepository.findById(parentId).orElse(null);
            if (upperOrgDO == null) {
                return Wrapper.fail(ResponseCode.MC_MS_ORGANIZATION_DOES_NOT_EXIST);
            }
        }

        MemberOrganizationDO organizationDO = new MemberOrganizationDO();
        organizationDO.setMember(memberDO);
        organizationDO.setTitle(orgName);
        organizationDO.setCode(StringUtils.hasLength(orgCode) ? orgCode.trim() : "");
        organizationDO.setParentId(parentId);
        organizationDO.setStore(memberStoreDO);

        //层级
        Integer level = upperOrgDO == null ? 1 : upperOrgDO.getLevel() + 1;
        organizationDO.setLevel(level);

        //在同父节点中的顺序
        int maxOrder = 0;
        if (!CollectionUtils.isEmpty(memberDO.getOrgs())) {
            if (upperOrgDO == null) {
                maxOrder = memberDO.getOrgs().stream().filter(org -> org.getLevel().equals(level)).mapToInt(MemberOrganizationDO::getOrder).max().orElse(0);
            } else {
                MemberOrganizationDO finalUpperOrgDO = upperOrgDO;
                maxOrder = memberDO.getOrgs().stream().filter(org -> org.getParentId().equals(finalUpperOrgDO.getId())).mapToInt(MemberOrganizationDO::getOrder).max().orElse(0);
            }
        }
        organizationDO.setOrder(maxOrder + 1);

        //生成Key
        String key = upperOrgDO == null ? String.valueOf(maxOrder + 1) : upperOrgDO.getKey().concat("-").concat(String.valueOf(maxOrder + 1));
        organizationDO.setKey(key);

        memberOrganizationRepository.save(organizationDO);

        return Wrapper.success();
    }

    /**
     * 根据菜单Id，更新组织机构信息
     * @param memberId 会员Id
     * @param updateVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> updateMemberOrg(Long memberId, MemberOrganizationUpdateVO updateVO) {
        MemberDO memberDO = memberRepository.findById(memberId).orElse(null);
        if (memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        MemberOrganizationDO organizationDO = memberDO.getOrgs().stream().filter(org -> org.getId().equals(updateVO.getId())).findFirst().orElse(null);
        if (organizationDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ORGANIZATION_DOES_NOT_EXIST);
        }

        organizationDO.setTitle(StringUtils.hasLength(updateVO.getTitle()) ? updateVO.getTitle() : "");
        organizationDO.setCode(StringUtils.hasLength(updateVO.getCode()) ? updateVO.getCode().trim() : "");
        organizationDO.setRemark(StringUtils.hasLength(updateVO.getRemark()) ? updateVO.getRemark().trim() : "");

        memberOrganizationRepository.saveAndFlush(organizationDO);

        return Wrapper.success();
    }

    /**
     * 删除一个会员组织架构
     * @param memberId 会员Id
     * @param deleteVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> deleteMemberOrg(Long memberId, MemberOrganizationDeleteVO deleteVO) {

        MemberDO memberDO = memberRepository.findById(memberId).orElse(null);
        if (memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        MemberOrganizationDO organizationDO = memberDO.getOrgs().stream().filter(org -> org.getId().equals(deleteVO.getId())).findFirst().orElse(null);
        if (organizationDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ORGANIZATION_DOES_NOT_EXIST);
        }

        List<MemberOrganizationDO> subOrgList = memberOrganizationRepository.findByMemberAndKeyStartsWith(memberDO, organizationDO.getKey());
        List<Long> subOrgIdList = subOrgList.stream().map(MemberOrganizationDO::getId).collect(Collectors.toList());

        //如果有用户已经关联了组织机构，不能删除
        if (memberDO.getUsers().stream().anyMatch(memberUserDO -> memberUserDO.getOrg() != null && subOrgIdList.contains(memberUserDO.getOrg().getId()))) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_ORG_CANNOT_DELETE_WHEN_USER_EXISTS);
        }

        memberOrganizationRepository.deleteInBatch(subOrgList);

        return Wrapper.success();
    }

    /**
     * 查询一个会员组织架构
     * @param memberId 会员Id
     * @param getVO    接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<MemberOrganizationQueryVO> getMemberOrg(Long memberId, MemberOrganizationGetVO getVO) {
        MemberDO memberDO = memberRepository.findById(memberId).orElse(null);
        if (memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        MemberOrganizationDO organizationDO = memberDO.getOrgs().stream().filter(org -> org.getId().equals(getVO.getId())).findFirst().orElse(null);
        if (organizationDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ORGANIZATION_DOES_NOT_EXIST);
        }

        MemberOrganizationQueryVO queryVO = new MemberOrganizationQueryVO();
        queryVO.setId(organizationDO.getId());
        queryVO.setTitle(organizationDO.getTitle());
        queryVO.setCode(organizationDO.getCode());
        queryVO.setRemark(organizationDO.getRemark());

        return Wrapper.success(queryVO);
    }

    /**
     * 查询会员的所有组织架构，以树形菜单的形式返回
     * @param memberId 会员Id
     * @return 操作结果
     */
    @Override
    public Wrapper<List<MemberOrgTreeVO>> treeMemberOrg(Long memberId) {
        MemberDO memberDO = memberRepository.findById(memberId).orElse(null);
        if (memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        return Wrapper.success(MemberOrganizationUtil.transferToTree(new ArrayList<>(memberDO.getOrgs())));
    }

    /**
     * 查询会员的（非门店）所有组织架构，以树形菜单的形式返回
     * @param memberId 会员Id
     * @return 查询结果
     */
    @Override
    public Wrapper<List<MemberOrgTreeVO>> nonStoreTreeMemberOrg(Long memberId) {
        QMemberOrganizationDO organizationDO = QMemberOrganizationDO.memberOrganizationDO;
        List<MemberOrganizationDO> orgList = jpaQueryFactory.select(organizationDO).from(organizationDO).where(organizationDO.member.id.eq(memberId).and(organizationDO.store.id.isNull())).fetch();

        return Wrapper.success(MemberOrganizationUtil.transferToTree(orgList));
    }


    /**
     * 查询会员的当前组织架构下单所有门店，用于订单数据权限
     * @param memberUserDO 会员用户信息
     * @return 门店ids
     */
    @Override
    public List<Long> getMemberOrgStoreIds(MemberUserDO memberUserDO, Long memberId) {
        if (memberUserDO == null) {
            return new ArrayList<>();
        }

        //当前组织机构id
        Long orgId;
        if (MemberUserAuthTypeEnum.ADMIN.getCode().equals(memberUserDO.getTypeEnum())) {
            //超级管理员查所以组织机构数据则parentId=0
            orgId = 0L;
        } else {
            if (memberUserDO.getOrg() == null) {
                return new ArrayList<>();
            }
            orgId = memberUserDO.getOrg().getId();
        }

        QMemberOrganizationDO qMemberOrganizationDO = QMemberOrganizationDO.memberOrganizationDO;
        JPAQuery<MemberOrgTreeBO> query = jpaQueryFactory.select(
                        Projections.constructor(MemberOrgTreeBO.class,
                                qMemberOrganizationDO.id,
                                qMemberOrganizationDO.parentId,
                                qMemberOrganizationDO.store.id
                        )).from(qMemberOrganizationDO)
                .where(qMemberOrganizationDO.member.id.eq(memberId));

        List<MemberOrgTreeBO> orgTreeList = query.fetch();
        List<Long> storeIds = new ArrayList<>();
        MemberOrganizationUtil.buildOrgTree(orgTreeList, orgId, storeIds);
        return storeIds;
    }
}
